import paramiko

import warnings
warnings.filterwarnings(action='ignore',module='.*paramiko.*')
import logging
import util_farms
import io
import json
import os
import cfg
import time
import sys
# logging.basicConfig()
logging.getLogger("paramiko").setLevel(logging.DEBUG)

log = logging.getLogger(util_farms.module_name+'.'+__name__)

class SSHClientChann():
    
    def __init__(self,host,user,passwd,token):
        self.host = host
        self.user = user
        self.passwd = passwd
        self.token =  token
        self.sftp = None
        self.__setup()
    
    def __setup(self):
        log.debug('Try to set up SSH channel on host [{}]'.format(self.host))
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())



        def interactive_handler(title, instructions, prompt_list):
            '''
            keyboard-interactive authentication
            '''
            log.debug('keyboard-interactive:title={} instructions={} prompt_list={}'.format(title, instructions, prompt_list))
            answer=[]
            if prompt_list:
                if str(prompt_list[0][0]).strip() == 'Password:':
                    answer.append(self.passwd)
                elif str(prompt_list[0][0]).strip() == 'Token:':
                    answer.append(self.token)                    
            log.debug('Answer: {}'.format(answer))
            return answer

        try:
            key_filename = None
            if os.path.exists(cfg.ddan_key_file):
                log.debug('Add DDAN key auth: {}'.format(cfg.ddan_key_file))
                key_filename = cfg.ddan_key_file
            self.client.connect(self.host,username=self.user,look_for_keys=False, allow_agent = False,password=self.passwd,key_filename=key_filename)
        except paramiko.ssh_exception.BadAuthenticationType as e:
            log.debug(e)
            if 'publickey' in e.allowed_types:
                log.info(util_farms.Colored.yellow('Need key {} do publickey auth'.format(cfg.ddan_key_file)))
                sys.exit(1)
            if 'keyboard-interactive' in e.allowed_types:
                self.client.get_transport().auth_interactive(username=self.user, handler=interactive_handler)
        except paramiko.ssh_exception.SSHException as e:
            self.client.get_transport().auth_interactive(username=self.user, handler=interactive_handler)
    
    def __del__(self):
        self.client.close()
        if self.sftp:
            self.sftp.close()

    def exec_command(self,cmd):
        '''
        Return: status, file handler
        '''
        log.debug('Execute {}'.format(cmd))
        try:
            stdin,stdout,stderr =  self.client.exec_command(cmd,timeout=10)
            if stdout.channel.recv_exit_status() != util_farms.Result.EXIT_CODE_OK.value:
                log.error('No zero exit code: {} for cmd {}'.format(stdout.channel.recv_exit_status(),cmd))
                return util_farms.Result.FAIL, io.BytesIO(('[{}]|{}|{}'.format(stdout.channel.recv_exit_status(),stdout.read(),stderr.read())).encode('utf-8'))
            return util_farms.Result.OK,stdout
        except paramiko.SSHException:
            if stderr:
                error = stderr.read()
            else:
                error=''
            log.error('Fail to execute the command {}:error {}'.format(cmd,error))
            return util_farms.Result.FAIL,io.BytesIO('ssh error')   
    
    def exec_dict(self,cmd):
        '''
        Parse output JSON to dict
        '''
        ret, out = self.exec_command(cmd)
        if ret == util_farms.Result.OK:
            try:
                _out = out.read().decode("utf-8")
                log.debug('Output:{}'.format(_out))
                return util_farms.Result.OK,  json.loads(_out)
            except json.decoder.JSONDecodeError:
                try:
                    import ast
                    return util_farms.Result.OK, ast.literal_eval(_out)
                except:
                    log.error('cout not parse to json {}'.format(_out))
                    return util_farms.Result.FAIL, out
            except:
                log.error('cout not parse to json {}'.format(_out))
                return util_farms.Result.FAIL, out
        return ret, out.read().decode("utf-8")
        
    def exec_simple(self,cmd):
        '''
        Parse output text to list
        '''
        ret, out = self.exec_command(cmd)
        return ret, out.read().decode("utf-8").split('\n')

    def test(self):
        ret, out = self.exec_command('ls -l')
        if ret == util_farms.Result.OK:
            print(out.read())
        else:
            log.error('fail to connect host {} by SSH'.format(self.host))
    
    def __sftp_open_check(self):
        if not self.sftp:
            self.sftp = self.client.open_sftp()
    
    def list(self):
        self.__sftp_open_check()
        print(self.sftp.listdir('./'))


class SSHClient():
    
    def __init__(self,host,user,passwd,token):
        self.host = host
        self.ssh = SSHClientChann(self.host,user,passwd,token)
    
    @util_farms.checkResult('U-sandbox version Checking')
    def checkUsbVersion(self,target = None):
        ret, out = self.ssh.exec_simple('/var/app_data/U-Sandbox/u-sandbox/usandbox/cli/usbxcli.py version')
        if ret != util_farms.Result.OK:
            raise util_farms.ManuleCheckException(self.host,'Fail to check Usandbox Version Info')
        
        result = [('Module','Version')]
        uSandboxVersion = ''
        for i in out:
            if len(str(i)) == 0 or str(i).startswith('Copyright'):continue
            v = str(i).split(':')
            if len(v) != 2:
                log.warning('unprocess info {}'.format(v))
                continue
            if v[0] == 'U-Sandbox':
                uSandboxVersion=str(v[1]).strip()
            result.append((v))
        util_farms.printTable('[{}]U-Sandbox Pattern/Engine Detail Version'.format(self.host),result)
        
        if target is not None and target != uSandboxVersion:
            raise util_farms.ManuleCheckException(self.host,'U-Sandbox [{}] do NOT equal target [{}]'.format(uSandboxVersion,target))
        
        return util_farms.Result.FEATURE_PASS
    
    @util_farms.checkResult('U-Sandbox image info check')
    def checkUsbImage(self,targetGroupNameCountInfo = None, targetStatus=None):
        ret, out = self.ssh.exec_dict('/var/app_data/U-Sandbox/u-sandbox/usandbox/cli/usbxcli.py sbxgrp-list')

        if ret != util_farms.Result.OK:
            raise util_farms.ManuleCheckException(self.host,'Fail to check Usandbox image Info')
       
        result = [('GroupName','InstanceCount','InstanceStatus')]        
        for grp in out.get('SandboxGroup',[]):
            _grp = []
            _grp.append(grp.get('Name',util_farms.Result.EMPTY_VALUE))
            _grp.append(len(grp.get('Sandboxes')))
            _grp.append([i.get('Status') for i in grp.get('Sandboxes')])
            result.append(_grp)
        util_farms.printTable('[{}]U-Sandbox Image Detail Info'.format(self.host),result)
        
        if targetGroupNameCountInfo:
            targetName = targetGroupNameCountInfo.keys()
            if util_farms.checkNotEqual(targetName,[i[0] for i in result[1:]]):
                raise util_farms.ManuleCheckException(self.host,'Usb group name [{}] do NOT equal target [{}]'.format([i[0] for i in result[1:]],targetName))
            
            _result = dict([(i[0],i[1]) for i in result[1:]])            
            for name,count in targetGroupNameCountInfo.items():
                if name in _result:
                    if count != _result[name]:
                        raise util_farms.ManuleCheckException(self.host,'Usb group name [{}] count [{}] do NOT equal target count [{}]'.format(name, _result[name],count))
        if targetStatus:
            if util_farms.checkNotEqual(targetStatus,[y for i in result[1:] for y in i[2]]):
                raise util_farms.ManuleCheckException(self.host,'Usb Instance Status [{}] do NOT equal target [{}]'.format([y for i in result[1:] for y in i[2]],targetStatus))
        return util_farms.Result.FEATURE_PASS
    
    @util_farms.checkResult('Tip/Flag check')
    def checkFlagTip(self):
        ret ,out = self.ssh.exec_dict('python /var/tmp/ddan/common/get_install_result.py')
        if ret != util_farms.Result.OK:
            raise util_farms.ManuleCheckException(self.host,'Fail to check Install/Migration flag info')
        log.info(out)
        if out.get('type') == 'upgrade':
            if out.get('result') == 1 or out.get('_tip_other_') == 1 or out.get('_tip_rpm_') == 1:
                raise util_farms.ManuleCheckException(self.host,'ERR_MIGRATE_FAILED')
            if out.get('_tip_va_isolated_') == 1:
                raise util_farms.ManuleCheckException(self.host,'WARN_CHANGE_TO_ISOLATED')
            if out.get('_tip_hostname_') == 1:
                raise util_farms.ManuleCheckException(self.host,'WARN_HOST_NAME_CHANGED')
            if out.get('_tip_pbagent_') == 1:
                raise util_farms.ManuleCheckException(self.host,'WARN_PBAGENT_UPGRADE_FAILED')
            if out.get('_tip_usandbox_') == 1:
                raise util_farms.ManuleCheckException(self.host,'ERR_USANDBOX_UPGRADE_FAILED')
            if out.get('_tip_db_') == 1:
                raise util_farms.ManuleCheckException(self.host,'ERR_DB_UPGRADE_FAILED')
        elif out.get('result') == 1:
            raise util_farms.ManuleCheckException(self.host,'ERR_INSTALL_FAILED')
        else:
            log.error('unsupport mode')
        return util_farms.Result.FEATURE_PASS
    
    def setMaintenance(self,onff=0):
        if onff == 0:
            log.info('Disable Maintenance mode')
        else:
            log.info('Enable Maintenance mode')
        ret, out = self.ssh.exec_dict('''python /opt/TrendMicro/DTAS/ddaaas_agent/ddaaasctl.py  -update_setting '{"maintenance_mode":"%d"}' '''%onff)
        if ret == util_farms.Result.OK and out.get('error_code') == 0:
            log.debug('Maintenance operation sucessfully')
            return util_farms.Result.OK
        return util_farms.Result.FAIL
    
    def checkReadyMaintenance(self):
        ret, out = self.ssh.exec_dict('''python /opt/TrendMicro/DTAS/ddaaas_agent/ddaaasctl.py -count''')
        if ret == util_farms.Result.OK and out.get('error_code') == 0:
            return out.get('total_count')
        log.error('Error {}'.format(out))
        return util_farms.Result.ERROR

    def enableLocalTestmode(self,fakeFQDN,farmsWithProxy):
        self.setMaintenance(onff=1)
        
        while True:
            ret = self.checkReadyMaintenance()
            if  ret != 0:
                log.info('Maintenance Not Ready [{}]'.format(ret))
                time.sleep(5)
            else:
                break 
        ret, result = self.ssh.exec_dict('''python /opt/TrendMicro/DTAS/ddaaas_agent/ddaaasctl.py -update_setting '{"localtest_mode":"1"}' ''')
        if ret == util_farms.Result.OK and result['error_code'] == 0:
            log.info('enable localtest mode sucessfully')
        else:
            log.error('fail to enable localtest mode {}'.format(result))
            return False
        if not fakeFQDN.startswith('https://'):
            fakeFQDN = 'https://'+fakeFQDN
        ret, result = self.ssh.exec_dict('''python /opt/TrendMicro/DTAS/ddaaas_agent/ddaaasctl.py -register '{"holder_id":"-1","server_url":"%s","server_groupid":"default","server_proxy_enable":"%s"}' '''%(fakeFQDN,farmsWithProxy))
        if ret == util_farms.Result.OK and result['error_code'] == 0:
            log.info('register fake server sucessfully')
        else:
            log.error('fail to register fake server {}'.format(result))
            return False
        return True

    def disableLocalTestmode(self):
        log.info('Try to disable Localtest mode')
        ret, result = self.ssh.exec_dict('''python /opt/TrendMicro/DTAS/ddaaas_agent/ddaaasctl.py -update_setting '{"localtest_mode":"0"}' ''')
        if ret == util_farms.Result.OK and result['error_code'] == 0:
            log.info('disable localtest mode sucessfully')
        else:
            log.error('fail to disable localtest mode {}'.format(result))
        ret, result = self.ssh.exec_dict('''python /opt/TrendMicro/DTAS/ddaaas_agent/ddaaasctl.py -unregister -holder_id -1''')
        if ret == util_farms.Result.OK and result['error_code'] == 0:
            log.info('unregister fake server sucessfly')
        else:
            log.error('fail to unregister fake server {}'.format(result))
        self.setMaintenance(onff=0) 
    
    @classmethod
    def clearnDDcloudMySQL(cls,host):
        ret, out = util_farms.exec_cmd('''mysql -h %s  -uroot -proot sandstorm -e 'delete from summary' '''%host)
        if ret:
            log.info('clean summary table sucessfully')
        else:
            log.error('unable to clean summary table')
    
    @classmethod
    @util_farms.checkResult('OMSA check')
    def checkOMSALocal(cls,host):
        ret, out = util_farms.exec_cmd('''perl /src/check_openmanage -s -H %s -C public --protocol 1 --only batteries -b ctrl=0/bat_charge=all -p'''%host)        
        if ret and out.startswith('BATTERIES OK'):
            log.info('OMSA check ok')
            return util_farms.Result.FEATURE_PASS
        else:
            raise util_farms.ManuleCheckException(host,'OMSA check fail')
    
    @classmethod
    def getGroupFromDDD(cls,**kwargs):
        ssh = SSHClientChann(**kwargs)
        ret , out = ssh.exec_simple("psql pixiebob pixiebob -tc 'select t.guid,t.display_name,t.type_,t.parent_guid,d.device_ips,t.product_type from tb_device_info as d right join tb_tree_node  as t on d.guid=t.guid order by t.type_ asc;'")
        
        device_lists = {}
        dir_name_guid = {}
        detail = [('guid','display_name','type_', 'parent_guid', 'device_ips','product_type')]
        group_info = {}
        if ret == util_farms.Result.OK:
            for i in out[1:]:
                d = i.split('|')
                if len(d) != 6:
                    continue
                guid, display_name, type_, parent_guid, device_ips,product_type = [str(j).strip() for j in d]
                detail.append(d)
                if str(type_) == str(1):
                    dir_name_guid[guid] = display_name
                elif str(product_type) == str(31008):
                    if parent_guid in dir_name_guid:
                        ips = device_ips.replace('{','').replace('}','').split(',')
                        if dir_name_guid.get(parent_guid) in group_info:
                            group_info[dir_name_guid.get(parent_guid)].append(ips[0])
                        else:
                            group_info[dir_name_guid.get(parent_guid)] = []
                            group_info[dir_name_guid.get(parent_guid)].append(ips[0])
                else:
                    log.debug('other device:{}'.format(d))
        util_farms.printTable('DDD Device List Detail',detail)
        return group_info

if __name__ == "__main__":

    import sys
    logging.basicConfig()
    logging.getLogger(util_farms.module_name).setLevel(logging.DEBUG)

    cfg = cfg.Configure()
    ssh = SSHClient(user='root',passwd='Admin1234!',host='10.64.1.129',token='eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJ1c2VyQDE2My5jb20iLCJpc3MiOiJ1c2VyMkAxNjMuY29tIiwibmJmIjoxNTI2MTc3NjY0LCJpYXQiOjE1NTcyNTI4NjQsImV4cCI6MTU1NzMxNzY2NCwiYXVkIjoiRERBTiIsImp0aSI6IjQ5MzhDRDc4LUFEQ0QtNDgwNS1COUZELUEzQ0RBRDIxODVFRSIsImxpYyI6WyJiMzBjMjlmMmI1OTg0YmFjM2Y4MDk4ZWQ3MzZjODY4MTFkMjg1ODUzZWM4YjRkOGJiZmQzNDBjZDMwNWZlZDAwIl19.f6gM-MjSiVTPP9rHknPZ7Uh_uIg3OWIcISZrvUdlL6f81GXzCEnD96Xb9KeLRQAFrIyQaOgYgo76O1v4uQP3FQ')
    # ssh.exec('ls -l ')
    # ssh.list()
    # ssh.list()
    # ssh.exec('cat /opt/ddan_installed')


    # ssh = SSHClient(user='root',passwd='admin',host='10.206.64.91',token='eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhNGRlNzQxZC01MzIxLTRjZDUtYmI1YS00ZTA1N2VlMzVlNWMiLCJzdWIiOiJ0b255X3N1QHRyZW5kbWljcm8uY29tLmNuIiwiZXhwIjoxNTQ2MzAwNzk5LCJsaWMiOlsiNzI5ZDU3ZDY4NWFlMWViZmYwMzBiMGFlYWZjNGFlY2RkMWUzZmRmZGM4YTBkMmY5MTUzODk1MzYzODhiMDYyYyJdLCJpc3MiOiJkYXZpZF9rb0B0cmVuZC5jb20udHciLCJpYXQiOjE1MjAzMDY2NzksIm5iZiI6MTUyMDMwNjY3OSwiYXVkIjpbIkRERCJdfQ.sEysfRSIQzW0svSgtc36PAoi2J7F-gfodVtAsw_mKHx7Ym9llVdbdqXJTCv2JORP1EX7mmr2kqBAG4hdRay80A')
    # ssh.ssh.test()
    # print(ssh.checkUsbVersion())
    print(ssh.checkUsbImage(cfg.getTargetUsbx().get('groupNameCountInfo',None),cfg.getTargetUsbx().get('instanceStatus',None)))
    ssh.checkFlagTip()
